// 'ob' == offset binary
// 'tag' == Write line numbers before each line output
//
//  TODO: 目前的版本中，从bin文件提取“波形”数据、CDS处理、写入fits文件等功能，全部在
//          同一个函数中实现，代码显得臃肿，不便于后期的更新维护。
//	@2021-10-08:PL端不再将“行号”写入PS端DDR中，因此这里也不再需要使用"cfg->HAS_TAG"

#include "ccd290_extract.h"

void extract_ccd290_16ch_csst(  char bin_file[], 
                                char fits_file[], 
                                char key_file[],
                                ccd290_config* cfg ) {

	printf("--> calling %s:%s\n", __FILE__, __func__);
    printf("--> reading binary data from: %s\n", bin_file);

    FILE *fb = fopen(bin_file,"rb");

    int bits_shift = 0;

    int num = cfg->LEN*CH_NUM + CH_NUM*bits_shift;	// total number of 'uint32_t'. 目前FPGA端还未调整好地址递增的问题...
    float *regs = (float*)malloc(sizeof(float)*num);
    int num_chk = fread(regs, sizeof(uint32_t), num, fb);

    if( num_chk != num ){
    	printf("(%s:L:%d) Error in reading binary data: %s\n", __FILE__, __LINE__, bin_file);
    	printf("@ num_chk = %d\n", num_chk);
    	printf("@ num     = %d\n", num);
    	exit(0);
    }

    fclose(fb);

    float *OS1  = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS2  = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS3  = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS4  = (float*)malloc(sizeof(float)*cfg->LEN);

    float *OS5  = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS6  = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS7  = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS8  = (float*)malloc(sizeof(float)*cfg->LEN);

    float *OS9  = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS10 = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS11 = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS12 = (float*)malloc(sizeof(float)*cfg->LEN);

    float *OS13 = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS14 = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS15 = (float*)malloc(sizeof(float)*cfg->LEN);
    float *OS16 = (float*)malloc(sizeof(float)*cfg->LEN);

    int i, cnt=0;
    int i_start = CH_NUM;

    for(i=i_start; i<num; i+=CH_NUM) {

        float fdata_OS1  = regs[i+0];
        float fdata_OS2  = regs[i+1];
        float fdata_OS3  = regs[i+2];
        float fdata_OS4  = regs[i+3];

        float fdata_OS5  = regs[i+4];
        float fdata_OS6  = regs[i+5];
        float fdata_OS7  = regs[i+6];
        float fdata_OS8  = regs[i+7];

        float fdata_OS9  = regs[i+8];
        float fdata_OS10 = regs[i+9];
        float fdata_OS11 = regs[i+10];
        float fdata_OS12 = regs[i+11];

        float fdata_OS13 = regs[i+12];
        float fdata_OS14 = regs[i+13];
        float fdata_OS15 = regs[i+14];
        float fdata_OS16 = regs[i+15];

    //  ====================
    //  重要:需要注意EFGH的顺序
    //  ====================

/*        int OS_OFFSET = 65535;*/

        OS1[cnt]  = fdata_OS1;
        OS2[cnt]  = fdata_OS2;
        OS3[cnt]  = fdata_OS3;
        OS4[cnt]  = fdata_OS4;

        OS5[cnt]  = fdata_OS5;
        OS6[cnt]  = fdata_OS6;
        OS7[cnt]  = fdata_OS7;
        OS8[cnt]  = fdata_OS8;

        OS9[cnt]  = fdata_OS9;
        OS10[cnt] = fdata_OS10;
        OS11[cnt] = fdata_OS11;
        OS12[cnt] = fdata_OS12;

        OS13[cnt] = fdata_OS13;
        OS14[cnt] = fdata_OS14;
        OS15[cnt] = fdata_OS15;
        OS16[cnt] = fdata_OS16;
        
        cnt++;
    }

//	CDS
    int pixel_num_total = cfg->N_ROW * cfg->N_COL * CH_NUM;
    printf("pixel_num_total = %d\n", pixel_num_total);
    printf("pixel_num_total/16 = %d\n", pixel_num_total/16);

    float *ccd = (float*)malloc( sizeof(float) * pixel_num_total );
    uint16_t *ccd_uint16 = (uint16_t*)malloc( sizeof(uint16_t) * pixel_num_total );
    
    for( i = 0; i < pixel_num_total; i++ ) {
        ccd[i]          = 0;
        ccd_uint16[i]   = 0;
    }

//  get offset from ccd290_config * cfg
	uint idx_offset = cfg->idx_offset;

    printf("idx_offset = %d\n", cfg->idx_offset);
    printf("cfg->LEN = %d\n", cfg->LEN);

//  开始拼接图像

    int row_cnt=0, col_cnt=0;
    int pix_idx;    //每个通道的像元计数器
	double nsample = cfg->cds_weight;

    for( pix_idx = idx_offset; pix_idx < cfg->LEN; pix_idx += cfg->SAMP_NUM_PER_REG) {
    
    //  以下idx可以保证拼接完之后就是正常的图像,但是与邵立要求的数据格式存在一定的差异,调整idx的计算方式即可
/*        int idx_os1  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*1 - col_cnt - 1 );*/
/*        int idx_os2  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*2 - col_cnt - 1 );*/
/*        int idx_os3  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*3 - col_cnt - 1 );*/
/*        int idx_os4  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*4 - col_cnt - 1 );*/
/*        */
/*        int idx_os5  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*5 - col_cnt - 1 );*/
/*        int idx_os6  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*6 - col_cnt - 1 );*/
/*        int idx_os7  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*7 - col_cnt - 1 );*/
/*        int idx_os8  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*8 - col_cnt - 1 );*/
/*        */
/*        int idx_os9  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*9 - col_cnt - 1 );*/
/*        int idx_os10 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*10 - col_cnt - 1 );*/
/*        int idx_os11 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*11 - col_cnt - 1 );*/
/*        int idx_os12 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*12 - col_cnt - 1 );*/

/*        int idx_os13 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*13 - col_cnt - 1 );*/
/*        int idx_os14 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*14 - col_cnt - 1 );*/
/*        int idx_os15 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*15 - col_cnt - 1 );*/
/*        int idx_os16 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*16 - col_cnt - 1 );*/

        int idx_os1  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*0 + col_cnt + 1*0 );
        int idx_os2  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*1 + col_cnt + 1*0 );
        int idx_os3  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*2 + col_cnt + 1*0 );
        int idx_os4  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*3 + col_cnt + 1*0 );
        
        int idx_os5  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*4 + col_cnt + 1*0 );
        int idx_os6  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*5 + col_cnt + 1*0 );
        int idx_os7  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*6 + col_cnt + 1*0 );
        int idx_os8  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*7 + col_cnt + 1*0 );
        
        int idx_os9  = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*8 + col_cnt + 1*0 );
        int idx_os10 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*9 + col_cnt + 1*0 );
        int idx_os11 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*10 + col_cnt + 1*0 );
        int idx_os12 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*11 + col_cnt + 1*0 );

        int idx_os13 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*12 + col_cnt + 1*0 );
        int idx_os14 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*13 + col_cnt + 1*0 );
        int idx_os15 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*14 + col_cnt + 1*0 );
        int idx_os16 = ( row_cnt * cfg->N_COL * CH_NUM ) + ( cfg->N_COL*15 + col_cnt + 1*0 );

        ccd[idx_os1]    = ( OS1[pix_idx]  / nsample ) + cfg->cds_offset;
        ccd[idx_os2]    = ( OS2[pix_idx]  / nsample ) + cfg->cds_offset;
        ccd[idx_os3]    = ( OS3[pix_idx]  / nsample ) + cfg->cds_offset;
        ccd[idx_os4]    = ( OS4[pix_idx]  / nsample ) + cfg->cds_offset;
        ccd[idx_os5]    = ( OS5[pix_idx]  / nsample ) + cfg->cds_offset;
        ccd[idx_os6]    = ( OS6[pix_idx]  / nsample ) + cfg->cds_offset;
        ccd[idx_os7]    = ( OS7[pix_idx]  / nsample ) + cfg->cds_offset;
        ccd[idx_os8]    = ( OS8[pix_idx]  / nsample ) + cfg->cds_offset;
        ccd[idx_os9]    = ( OS9[pix_idx]  / nsample ) + cfg->cds_offset;
        ccd[idx_os10]   = ( OS10[pix_idx] / nsample ) + cfg->cds_offset;
        ccd[idx_os11]   = ( OS11[pix_idx] / nsample ) + cfg->cds_offset;
        ccd[idx_os12]   = ( OS12[pix_idx] / nsample ) + cfg->cds_offset;
        ccd[idx_os13]   = ( OS13[pix_idx] / nsample ) + cfg->cds_offset;
        ccd[idx_os14]   = ( OS14[pix_idx] / nsample ) + cfg->cds_offset;
        ccd[idx_os15]   = ( OS15[pix_idx] / nsample ) + cfg->cds_offset;
        ccd[idx_os16]   = ( OS16[pix_idx] / nsample ) + cfg->cds_offset;
        
/*        printf("--> debug ccd[%d] = %g\n", idx_os1, ccd[idx_os1]);*/

/*        ccd_uint16[idx_os1] = (uint16_t)(ccd[idx_os1]*4);*/
/*        ccd_uint16[idx_os2] = (uint16_t)(ccd[idx_os2]*4);*/
/*        ccd_uint16[idx_os3] = (uint16_t)(ccd[idx_os3]*4);*/
/*        ccd_uint16[idx_os4] = (uint16_t)(ccd[idx_os4]*4);*/

/*        ccd_uint16[idx_os5] = (uint16_t)(ccd[idx_os5]*4);*/
/*        ccd_uint16[idx_os6] = (uint16_t)(ccd[idx_os6]*4);*/
/*        ccd_uint16[idx_os7] = (uint16_t)(ccd[idx_os7]*4);*/
/*        ccd_uint16[idx_os8] = (uint16_t)(ccd[idx_os8]*4);*/

/*        ccd_uint16[idx_os9] = (uint16_t)(ccd[idx_os9]*4);*/
/*        ccd_uint16[idx_os10] = (uint16_t)(ccd[idx_os10]*4);*/
/*        ccd_uint16[idx_os11] = (uint16_t)(ccd[idx_os11]*4);*/
/*        ccd_uint16[idx_os12] = (uint16_t)(ccd[idx_os12]*4);*/

/*        ccd_uint16[idx_os13] = (uint16_t)(ccd[idx_os13]*4);*/
/*        ccd_uint16[idx_os14] = (uint16_t)(ccd[idx_os14]*4);*/
/*        ccd_uint16[idx_os15] = (uint16_t)(ccd[idx_os15]*4);*/
/*        ccd_uint16[idx_os16] = (uint16_t)(ccd[idx_os16]*4);*/

        ccd_uint16[idx_os1] = (ccd[idx_os1]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os1]*4);
        ccd_uint16[idx_os2] = (ccd[idx_os2]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os2]*4);
        ccd_uint16[idx_os3] = (ccd[idx_os3]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os3]*4);
        ccd_uint16[idx_os4] = (ccd[idx_os4]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os4]*4);
        
        ccd_uint16[idx_os5] = (ccd[idx_os5]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os5]*4);
        ccd_uint16[idx_os6] = (ccd[idx_os6]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os6]*4);
        ccd_uint16[idx_os7] = (ccd[idx_os7]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os7]*4);
        ccd_uint16[idx_os8] = (ccd[idx_os8]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os8]*4);
        
        ccd_uint16[idx_os9] = (ccd[idx_os9]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os9]*4);
        ccd_uint16[idx_os10] = (ccd[idx_os10]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os10]*4);
        ccd_uint16[idx_os11] = (ccd[idx_os11]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os11]*4);
        ccd_uint16[idx_os12] = (ccd[idx_os12]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os12]*4);
        
        ccd_uint16[idx_os13] = (ccd[idx_os13]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os13]*4);
        ccd_uint16[idx_os14] = (ccd[idx_os14]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os14]*4);
        ccd_uint16[idx_os15] = (ccd[idx_os15]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os15]*4);
        ccd_uint16[idx_os16] = (ccd[idx_os16]*4>=65535) ? 65535 : (uint16_t)(ccd[idx_os16]*4);
        
/*
    //  检查通道数据写入的位置是否正确
        ccd_uint16[idx_os1] = 100;
        ccd_uint16[idx_os2] = 200;
        ccd_uint16[idx_os3] = 500;
        ccd_uint16[idx_os4] = 700;
        
        ccd_uint16[idx_os5] = 900;
        ccd_uint16[idx_os6] = 1000;
        ccd_uint16[idx_os7] = 1300;
        ccd_uint16[idx_os8] = 1500;
        
        ccd_uint16[idx_os9] = 1700;
        ccd_uint16[idx_os10] = 1900;
        ccd_uint16[idx_os11] = 2100;
        ccd_uint16[idx_os12] = 2300;
        
        ccd_uint16[idx_os13] = 2500;
        ccd_uint16[idx_os14] = 2700;
        ccd_uint16[idx_os15] = 2900;
        ccd_uint16[idx_os16] = 3000;
*/

/*        ccd_uint16[idx_os1] = 100;*/
/*        ccd_uint16[idx_os2] = 60000;*/
/*        ccd_uint16[idx_os3] = 500;*/
    	col_cnt++;  // 必须先+1,然后再进行判断

        if( col_cnt >= cfg->N_COL ) {
            col_cnt -= cfg->N_COL;
            row_cnt++;
        }
    }

//	===================================================
//  write CDS process data into fits
    fitsfile *fptr;
    int status;
    long fpixel = 1, naxis = 2, nelements; //, exposure;
    
    long naxes[2] = {(cfg->N_COL + cfg->HAS_TAG)*CH_NUM, cfg->N_ROW}; // image's cols and rows
    
    if( cfg->include_line_num == 0 ){
    	naxes[0] = cfg->N_COL * CH_NUM;
    	naxes[1] = cfg->N_ROW;
    }

    status = 0;
    
	fits_create_file(&fptr, fits_file, &status); /* create new file */

    if( cfg->use_uint16_format == 1 ){
        fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status);
    } else {
        fits_create_img(fptr, FLOAT_IMG, naxis, naxes, &status);
    }

//	==============================================================================
    // 写入头文件信息
    add_fits_keywords_from_ini(fptr, key_file);

//	==============================================================================
//  写入图像数据
    nelements = naxes[0] * naxes[1];

    if( cfg->use_uint16_format == 1 ){
        fits_write_img(fptr, TUSHORT, fpixel, nelements, ccd_uint16, &status);
    } else {
        fits_write_img(fptr, TFLOAT, fpixel, nelements, ccd, &status);
    }
//	==============================================================================

    fits_close_file(fptr, &status);


    fits_report_error(stderr, status);
//	===================================================

    free(OS1);
    free(OS2);
    free(OS3);
    free(OS4);

    free(OS5);
    free(OS6);
    free(OS7);
    free(OS8);

    free(OS9);
    free(OS10);
    free(OS11);
    free(OS12);

    free(OS13);
    free(OS14);
    free(OS15);
    free(OS16);

    free(regs);
    free(ccd);
    free(ccd_uint16);

    printf("--> data saved into fits: %s\n", fits_file);
}


